﻿using System;
using WiMo.Games;
using System.Drawing;
using WiMo.Games.Drawables;
using wimo = WiMo.Games.Drawables;
using System.Drawing.Imaging;
using WiMo.Games.Premium.GDIDisplay.ImageAPI;
using Microsoft.Drawing;
using System.IO;

namespace WiMo.Games.Premium.GDIDisplay.Drawables
{
    public class SpriteImage : SpriteImageBase
    {
        private IImage _imagingImage;
        private IContentManager _contentManager;

        public SpriteImage()
        {
            IsVisible = true;
            Origin = Origin.Center;
            Force = Vector2.Zero;
            ColorKey = Color.Transparent;
            IsStatic = false;
            Position = PointF.Origin;
            Mass = 1;
            Torque = 0.0f;
            ImageIndex = 0;
            CollisionShape = CollisionShapes.Rectangle;
        }

        public override CollisionShapes CollisionShape
        {
            get { return base.CollisionShape; }
            set
            {
                CollisionDetectionPoints.Clear();

                if (TextureList != null &&
                    TextureList.Count > 0
                    && value == CollisionShapes.Sphere)
                {
                    var rads = 2.0f * Math.PI / 8.0f;
                    var radius = Size.Width / 2;

                    for (var idx = 0.0f; idx < 8f; ++idx)
                        CollisionDetectionPoints.Add(new Location(Math.Sin(rads * idx) * radius, Math.Cos(rads * idx) * radius));
                }

                base.CollisionShape = value;
            }
        }

        public override int ImageIndex
        {
            get { return base.ImageIndex; }
            set
            {
                if (base.ImageIndex != value)
                {
                    Invalidate();

                    if (_imagingImage != null)
                        _imagingImage = null;

                    //So we can refresh based upon the new image.
                    var disposable = DrawInformation as IDisposable;
                    if (disposable != null)
                    {
                        disposable.Dispose();
                        DrawInformation = null;
                    }

                    CollisionDetectionPoints.Clear();

                    //The sprite might be a different size.
                    if (TextureList.Count > 0 && CollisionShape == CollisionShapes.Sphere)
                    {
                        var rads = 2.0f * Math.PI / 8.0f;
                        var radius = Size.Width / 2;

                        for (var idx = 0.0f; idx < 8f; ++idx)
                            CollisionDetectionPoints.Add(new Location(Math.Sin(rads * idx) * radius, Math.Cos(rads * idx) * radius));
                    }

                    base.ImageIndex = value;
                }
            }
        }


        public override void Load(IContentManager contentManager, string name)
        {
            _contentManager = contentManager;
            var texture = contentManager.GetTexture(name);

            TextureList.Add(texture);

            CollisionDetectionPoints.Clear();

            if (CollisionShape == CollisionShapes.Sphere)
            {
                var rads = 2.0f * Math.PI / 8.0f;
                var radius = Size.Width / 2;

                for (var idx = 0.0f; idx < 8f; ++idx)
                    CollisionDetectionPoints.Add(new Location(Math.Sin(rads * idx) * radius, Math.Cos(rads * idx) * radius));
            }
        }

        private IImage LoadImagingImage(string name, string extension)
        {
            var assembly = _contentManager.Engine.Game.GetType().Assembly;
            var path = String.Format("{0}.{1}._{2}.{3}.{4}", assembly.FullName.Substring(0, assembly.FullName.IndexOf(',')), _contentManager.ContentLocation, _contentManager.Engine.Display.DPI, name.Replace("/", "."), extension);
            var stream = assembly.GetManifestResourceStream(path);
            if (stream == null)
            {
                path = String.Format("{0}.{1}.{2}.{3}", assembly.FullName.Substring(0, assembly.FullName.IndexOf(',')), _contentManager.ContentLocation, name.Replace("/", "."), extension);
                stream = assembly.GetManifestResourceStream(path);

                if (stream == null)
                    return null;
            }

            IImage image;
            var imageData = new byte[stream.Length];
            stream.Read(imageData, 0, (int)stream.Length);
            IImagingFactory factory = ImagingFactory.GetImaging();
            factory.CreateImageFromBuffer(imageData, (uint)imageData.Length, BufferDisposalFlag.BufferDisposalFlagNone, out image);
            stream.Dispose();

            //Need to read in to initialize.
            ImageInfo imageInfo;
            image.GetImageInfo(out imageInfo);

            System.Diagnostics.Debug.WriteLine(string.Format("IMAGE INFO -> {0} {1}x{2}", imageInfo.pixelFormat, imageInfo.Width, imageInfo.Height));

            return image;
        }        

        public override int AddImage(IContentManager contentManager, string name)
        {
            var bitmap = contentManager.GetTexture(name);

            TextureList.Add(bitmap);

            return TextureList.Count - 1;
        }

        private WiMoImage _wimoImage;

        public void Render(IDisplay display, WiMo.Games.Rectangle destRect)
        {
            var displayManager = display as DisplayManager;

            if(_wimoImage == null)
                _wimoImage = WiMoImage.Create(Texture.TextureInformation as Bitmap);

            _wimoImage.ImagingImage = ImagingImage;
            _wimoImage.RenderStrategy = RenderStrategy;
            _wimoImage.ColorKey = ColorKey;

            displayManager.Graphics.DrawImage(_wimoImage, new Location(BoundingRect.X + displayManager.DisplayOffset.X, BoundingRect.Y + displayManager.DisplayOffset.Y));

            //var targetRect = BoundingRect.GetIntersection(destRect);
            //var srcRect = new WiMo.Games.Rectangle(Math.Max(0, destRect.X - BoundingRect.X), Math.Max(0, destRect.Y - BoundingRect.Y), targetRect.Width, targetRect.Height);
            //if (targetRect.Size.Width == 0 || targetRect.Size.Height == 0)
            //    return;            

            //switch (RenderStrategy)
            //{
            //    case RenderStrategy.Standard:
            //    case RenderStrategy.Fast:
            //        displayManager.Graphics.DrawImage(Texture.TextureInformation as Bitmap, (targetRect + displayManager.DisplayOffset), srcRect, ColorKey);
            //        break;
            //    case RenderStrategy.Quality:
            //        var qualityRect = new WiMo.Games.Rectangle(targetRect.Left + displayManager.DisplayOffset.X, targetRect.Top + displayManager.DisplayOffset.Y, targetRect.Width, targetRect.Height);
            //        displayManager.Graphics.DrawImage(ImagingImage, qualityRect, srcRect);
            //        break;
            //}
        }


        public override void Render(IDisplay display)
        {
            Render(display, new WiMo.Games.Rectangle(0, 0, display.Size.Width, display.Size.Height));
        }

        public ITexture Texture
        {
            get { return TextureList[ImageIndex]; }
        }

        public override Size Size
        {
            get
            {
                var bitmap = Texture.TextureInformation as Bitmap;
                return new Size(bitmap.Width, bitmap.Height);
            }
            set { throw new Exception("Setting size of bitmap not supported."); }
        }

        public override RenderStrategy RenderStrategy
        {
            get { return base.RenderStrategy; }
            set {
                if (value != base.RenderStrategy)
                {
                    Invalidate();
                    base.RenderStrategy = value;
                }
            }
        }

        public override Size UnscaledSize
        {
            get { return new Size((int)(Size.Width / Scale.X), (int)(Size.Height / Scale.Y)); }
            set { throw new Exception("Setting size of bitmap not supported."); }
        }

        public Bitmap BitampImage
        {
            get { return TextureList[ImageIndex].TextureInformation as Bitmap; }
        }

        public IImage ImagingImage
        {
            get
            {
                if (_imagingImage == null)
                {
                    _imagingImage = LoadImagingImage(TextureList[ImageIndex].Name, "png");

                    if (_imagingImage == null)
                        _imagingImage = LoadImagingImage(TextureList[ImageIndex].Name, "bmp");
                }

                return _imagingImage;
            }
        }

        #region Rotation
        private float _rotation = 0.0f;
        public override float Rotation
        {
            get { return _rotation; }
            set
            {
                throw new NotImplementedException("Rotation in Windows Mobile not implemented.");
                //if (_rotation != value)
                //{
                //TextureList[ImageIndex].TextureInformation = OpenNETCF.Drawing.Imaging.ImageUtils.Rotate(TextureList[ImageIndex].TextureInformation as Bitmap, _rotation);
                //OpenNETCF.Drawing.RotationAngle rot;
                //_rotation = value;

                //var degs = (int)MathHelper.ToDegrees(_rotation);
                //switch (degs)
                //{
                //    case 0: rot = OpenNETCF.Drawing.RotationAngle.Zero; break;
                //    case 90: rot = OpenNETCF.Drawing.RotationAngle.Clockwise90; break;
                //    case 180: rot = OpenNETCF.Drawing.RotationAngle.Clockwise180; break;
                //    case 270: rot = OpenNETCF.Drawing.RotationAngle.Clockwise270; break;
                //    default:
                //        throw new Exception("Can only rotate images 0, 90, 180, 270.  I know this sucks, but it's currently a limitation on the device.  It's in our plan to change this.");
                //}
                //TextureList[ImageIndex].TextureInformation = OpenNETCF.Drawing.Imaging.ImageUtils.Rotate(Texture.TextureInformation as Bitmap, rot);
                //DrawInformation = null;
                //}

            }
        }
        #endregion

        public override void Dispose()
        {

        }
    }
}
